package com.snowballtech.retry;

import com.aliyun.openservices.ons.api.Message;
import com.aliyun.openservices.ons.api.Producer;
import com.aliyun.openservices.ons.api.SendResult;
import com.aliyun.openservices.shade.com.alibaba.fastjson.JSONObject;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.retry.RecoveryCallback;
import org.springframework.retry.RetryCallback;
import org.springframework.retry.RetryContext;
import org.springframework.retry.backoff.FixedBackOffPolicy;
import org.springframework.retry.policy.SimpleRetryPolicy;
import org.springframework.retry.support.RetryTemplate;

import java.util.Collections;
import java.util.Date;

/**
 * Description:
 *
 * @Author: genezhao
 * @Date: 2018-04-16
 */
public class MQRetry {

    private Logger log = LoggerFactory.getLogger(MQRetry.class);

    public static String WEBHOOK_TOKEN = "https://oapi.dingtalk.com/robot/send?access_token=85d6d7a9297c8c941283533c98808cf62ef525602912e1989666eb47155c23b7";

    RetryTemplate retryTemplate = new RetryTemplate();

    /**
     * 最大重试次数
     */
    private int maxAttempts = 3;

    /**
     * 重试间隔时间，默认1000ms
     */
    private int backOffPeriod = 1000;

    public MQRetry() {
        SimpleRetryPolicy policy = new SimpleRetryPolicy(this.maxAttempts, Collections.<Class<? extends Throwable>, Boolean>singletonMap(Exception.class, true));
        // 设置重试回退操作策略，主要设置重试间隔时间
        FixedBackOffPolicy fixedBackOffPolicy = new FixedBackOffPolicy();
        fixedBackOffPolicy.setBackOffPeriod(this.backOffPeriod);
        retryTemplate.setRetryPolicy(policy);
        retryTemplate.setBackOffPolicy(fixedBackOffPolicy);
    }

    public void send(final Retry retry) {
        try {
            // 由retryTemplate 执行execute方法开始逻辑执行
            retryTemplate.execute(retryCallback(retry), recoveryCallback(retry));
        } catch (Throwable e) {
            log.info("===重试回调异常==="+e.getMessage());
            e.printStackTrace();
        }
    }

    public void send(final Retry retry, boolean isDebug) {
        try {
            // 由retryTemplate 执行execute方法开始逻辑执行
            retryTemplate.execute(retryCallback(retry,isDebug), recoveryCallback(retry));
        } catch (Throwable e) {
            log.info("===重试回调异常==="+e.getMessage());
            e.printStackTrace();
        }
    }

    private RetryCallback retryCallback(final Retry retry, final boolean isDebug) {
        // 通过RetryCallback 重试回调实例包装正常逻辑逻辑，第一次执行和重试执行执行的都是这段逻辑
        final RetryCallback<Object, Exception> retryCallback = new RetryCallback<Object, Exception>() {

            @Override
            public Object doWithRetry(RetryContext context){
                SendResult sendResult = retry.getProducer().send(retry.getMessage());
                System.out.println(new Date() + " Send mq message success. Topic is:" + retry.getMessage().getTopic() + " msgId is: " + sendResult.getMessageId());
                if (isDebug){
                    throw new RuntimeException();
                }
                return sendResult;
            }
        };
        return retryCallback;
    }

    private RetryCallback retryCallback(final Retry retry) {
        // 通过RetryCallback 重试回调实例包装正常逻辑逻辑，第一次执行和重试执行执行的都是这段逻辑
        final RetryCallback<Object, Exception> retryCallback = new RetryCallback<Object, Exception>() {

            @Override
            public Object doWithRetry(RetryContext context){
                SendResult sendResult = retry.getProducer().send(retry.getMessage());
                System.out.println(new Date() + " Send mq message success. Topic is:" + retry.getMessage().getTopic() + " msgId is: " + sendResult.getMessageId());
                return sendResult;
            }
        };
        return retryCallback;
    }

    private RecoveryCallback recoveryCallback(final Retry retry) {
        // 通过RecoveryCallback 重试流程正常结束或者达到重试上限后的退出恢复操作实例
        final RecoveryCallback<Object> recoveryCallback = new RecoveryCallback<Object>() {
            @Override
            public Object recover(RetryContext retryContext) throws Exception {
                Message msg = retry.getMessage();
                log.info("::::::::::::正在发送钉钉监控报警::::::::::::");
                System.out.println(JSONObject.toJSONString(msg));
                HttpClient httpclient = HttpClients.createDefault();

                HttpPost httppost = new HttpPost(WEBHOOK_TOKEN);
                httppost.addHeader("Content-Type", "application/json; charset=utf-8");

                String msgStr = "Topic:"+msg.getTopic()+" msgID:"+msg.getMsgID()+" key:"+msg.getKey()+" tag:"+msg.getTag();

                String textMsg = "{ \"msgtype\": \"text\", \"text\": {\"content\": \"" + retry.getMonitorMessage().setMsg(msgStr).toString() + "\"}}";
                StringEntity se = new StringEntity(textMsg, "utf-8");
                httppost.setEntity(se);

                HttpResponse response = httpclient.execute(httppost);
                String result = "";
                if (response.getStatusLine().getStatusCode()== HttpStatus.SC_OK){
                    result = EntityUtils.toString(response.getEntity(), "utf-8");
                    log.info("钉钉监控响应 {}",result);
                }
                log.info("::::::::::::发送钉钉监控报警结束::::::::::::");
                return result;
            }
        };
        return recoveryCallback;
    }

    public void setMaxAttempts(int maxAttempts) {
        this.maxAttempts = maxAttempts;
    }

    public void setBackOffPeriod(int backOffPeriod) {
        this.backOffPeriod = backOffPeriod;
    }
}
